import {ConnectConfig} from "ssh2";
import ssh2 = require("ssh2");
var Client = require('ssh2').Client;

export class SSHClient {
    conn:ssh2.Client = new Client();
    shellStream:ssh2.Channel;

    constructor() {
    }

    close() {
        this.conn.end();
    }

    shell():Promise<void> {
        return new Promise<void>((resolve, reject)=> {
            this.conn.shell((err:Error, stream:ssh2.Channel) => {
                if (err) {
                    reject(err);
                    return;
                }

                this.shellStream = stream;
                var stdin = process.stdin
                stdin.on('data', (chunk)=> {
                    this.shellStream.write(chunk);
                });

                stream.stderr!.on('data', (data:any) => {
                    console.error('STDERR: ' + data);
                    if (this.execPromiseReject)
                        this.execPromiseReject(new Error('STDERR: ' + data));
                    else
                        reject(new Error('STDERR: ' + data));
                });

                stream.on('close', () => {
                    console.log('Stream :: close');
                    //this.conn.end();
                    if (this.execPromiseResolve)
                        this.execPromiseResolve();
                    else
                        resolve();
                });

                stream.on('end', () => {
                    console.log('Stream :: end');
                    //resolve();
                });

                stream.on('data', (data:any) => {
                    //let ret='Stream :: data\r\n' + data
                    let ret = "" + data;

                    if (ret.length > 1) {

                        if (ret.endsWith("# ")) {
                            if (this.execPromiseResolve)
                                this.execPromiseResolve();
                            else
                                resolve();
                        }
                        else if (this.execLastString && ret.endsWith(this.execLastString)) {
                            if (this.execPromiseResolve)
                                this.execPromiseResolve();
                            else
                                resolve();
                        }

                    }
                    console.error(ret);
                    // if (res)
                    //     res(data);
                });
            });
        });
    }

    execPromiseResolve?:()=>void;
    execPromiseReject?:(err:Error)=>void;
    execLastString?:string;

    exec(command:string, execStr?:string, res?:(res:string)=>void):Promise<void> {
        this.execLastString = execStr;
        return new Promise<void>((resolve, reject)=> {
            // this.conn.exec(command, (err:Error, stream:ssh2.Channel) => {
            //     if (err) {
            //         reject(err);
            //         return;
            //     }
            //     stream.on('close', (code:any, signal:any) => {
            //         console.log('Stream :: close :: code: ' + code + ', signal: ' + signal);
            //         this.conn.end();
            //         resolve();
            //     }).on('data', (data:any) => {
            //         console.warn('STDOUT:\r\n' + data);
            //         res(data);
            //     });
            // });
            this.execPromiseResolve = resolve;
            this.execPromiseReject = reject;
            this.shellStream.write(command + "\n");
        });
    }

    connect(config:ConnectConfig):Promise<void> {
        return new Promise<void>((resolve, reject)=> {
            this.conn.on("ready", () => {
                resolve();
            });

            this.conn.on("error", err=> {
                reject(err);
                console.error("error" + err);
            });

            this.conn.connect(config);
        });
    }


}